#include <iostream>
#include <random>
#include <cassert>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstring>
#include <functional>
#include <unistd.h>
#include <ctime>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <unordered_map>
#include <string>

using namespace std ;
// 父进程控制多个子进程来共同完成任务
vector<function<void()>> fcntors;
unordered_map<uint32_t, string> infomap;

void Load() {
    infomap.emplace(fcntors.size(), "处理日志");
    fcntors.push_back([](){ cout << "这是负责处理日志的函数  time: " << time(nullptr) << endl; });

    infomap.emplace(fcntors.size(), "备份数据");
    fcntors.push_back([](){ cout << "这是负责备份数据的函数  time: " << time(nullptr) << endl; });

    infomap.emplace(fcntors.size(), "网络连接");
    fcntors.push_back([](){ cout << "这是负责网络连接的函数  time: " << time(nullptr) << endl; });
}

typedef pair<int32_t, int32_t> procMgt;
int processNum = 5; // 子进程的个数

void work(int blockFd) {
    cout << "pid 为 [" << getpid() << "] 的子进程开始工作" << endl;
    while (true) {
        // 读取管道里面的数据，并执行
        uint32_t optype = 0; // 管道中读取到的数据
        ssize_t rdret = read(blockFd, &optype, sizeof(uint32_t));
        if (rdret == 0) { // 写端关闭，那么读端也跟着关闭
            break;
        }
        assert(rdret >= 0);
        (void)rdret; // release 下别报警告
 
        // 执行任务
        if (optype < fcntors.size()) 
            fcntors[optype](); // 执行方法

        cout << endl;
    }
    
    cout << "pid 为 [" << getpid() << "] 的子进程结束工作" << endl;
}

void sendTask(const vector<procMgt>& assigner) {
    srand((long long) time(nullptr)); // rand number
    while (true) {
        uint32_t pick = rand() % processNum; // choose a child process
        uint32_t task = rand() % fcntors.size(); // choose a task

        write(assigner[pick].second, &task, sizeof(uint32_t));

        cout << "父进程指派任务 -> [" << infomap[task] << "] 给子进程 [" 
             << assigner[pick].first << "] 编号 [" << pick << "]" << endl;

        sleep(1);
    }
}

int main() {
    Load();
    // pair(pid, 管道写端fd)
    vector<procMgt> assigner;

    // 为这些子进程分配任务，需要通过管道来实现
    // 那么就依靠两个属性：pair(pid, 管道)
    for (int i = 0; i < processNum; i ++) {
        int pipefd[2] = {0};
        if (pipe(pipefd) != 0) { //  = 0 表示创建成功
            cerr << "pipe error" << endl;
        }

        pid_t pid = fork();
        if (pid == 0) { // 子进程执行
            // child  read
            close(pipefd[1]);
            // child process start to perform
            work(pipefd[0]);
            close(pipefd[0]); 
            exit(0);
        }

        // parent   write
        close(pipefd[0]);
        assigner.emplace_back(pid, pipefd[1]); // add child process info
    }
    cout << "create all child processes successfully !" << endl;
    // 父进程到这里，指派任务
    sendTask(assigner);

    // 回收资源
    for (int i = 0; i < processNum; i ++) {
        if (waitpid(assigner[i].first, nullptr, 0) > 0) 
            cout << "wait for: " << assigner[i].first << "successfully" 
                 << "index: " << i << endl;

        close(assigner[i].second);
    }
}